//
// AWS Manager - A free AWS console application demonstrating advanced concepts
// Copyright (C) 2008-2010 Sean O'Dell. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.awsmanager.common;

import com.sun.data.provider.RowKey;
import com.sun.data.provider.impl.ObjectListDataProvider;
import com.sun.webui.jsf.model.Option;
import com.xerox.amazonws.ec2.ConsoleOutput;
import com.xerox.amazonws.ec2.EC2Exception;
import java.util.ArrayList;
import java.util.List;

import com.xerox.amazonws.ec2.Jec2;
import com.xerox.amazonws.ec2.ReservationDescription;
import com.xerox.amazonws.ec2.ReservationDescription.Instance;
import com.xerox.amazonws.ec2.InstanceStateChangeDescription;
import com.xerox.amazonws.sdb.Domain;
import com.xerox.amazonws.sdb.Item;
import com.xerox.amazonws.sdb.ItemAttribute;
import com.xerox.amazonws.sdb.QueryWithAttributesResult;
import com.xerox.amazonws.sdb.SDBException;
import com.xerox.amazonws.sdb.SimpleDB;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Sean ODell
 */
public class EC2InstanceDataProvider extends ObjectListDataProvider {

    private ArrayList ec2InstanceList = new ArrayList();
    private EC2Connection ec2connection;
    private Jec2 ec2;
    private SimpleDB simpleDB;
    private Domain sdbdomain = null;

    /** Creates a new instance of AddressDataProvider */
    public EC2InstanceDataProvider() {
        setList(ec2InstanceList);
        setObjectType(EC2Instance.class);
    }

    public void load(EC2Connection ec2connection, SDBConnection sdbconnection) {

        clearObjectList();

        if (ec2connection == null) {
            this.ec2 = null;
            return;
        }

        if (ec2connection == null) {
            this.ec2connection = null;
            return;
        } else {
            this.ec2connection = ec2connection;
        }

        if ((this.ec2connection = ec2connection) == null) {
            return;
        }

        Item sdbitem = null;
        List<ItemAttribute> sdbattributes = null;
        String sdbdomainname = null;
        String sdbdomainsuffix = "";
        Map sdbInstanceItems = null;

        ArrayList<String> sdbattributesList = new ArrayList<String>();
        sdbattributesList.add("type");
        sdbattributesList.add("name");
        sdbattributesList.add("description");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamefirst");
        sdbattributesList.add("ownerdept");

        sdbdomain = null;

        if ((simpleDB = sdbconnection.getsimpleDB()) != null) {

            sdbdomainname = sdbconnection.getsdbdomain() + sdbdomainsuffix;

            try {
                sdbdomain = simpleDB.getDomain(sdbdomainname);
            } catch (SDBException ex) {
                sdbdomain = null;
                Logger.getLogger(EC2InstanceDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }

            try {
                sdbdomain.getItem("test").getAttributes();
            } catch (SDBException ex) {
                try {
                    sdbdomain = simpleDB.createDomain(sdbdomainname);
                } catch (SDBException ex1) {
                    Logger.getLogger(EC2InstanceDataProvider.class.getName()).log(Level.SEVERE, null, ex1);
                }
            }

            QueryWithAttributesResult queryResult = null;
            String nextToken = "";

            if (sdbdomain != null) {
                try {
                    queryResult = sdbdomain.selectItems("select * from "
                            + sdbdomainname + " where type = 'instance'", nextToken, true);
                } catch (SDBException ex) {
                    Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                }
                if (queryResult != null) {
                    sdbInstanceItems = queryResult.getItems();
                }
            }
        }

        List<String> params = new ArrayList<String>();
        List<ReservationDescription> ec2Instances = null;

        ArrayList<String> ec2Regions = ec2connection.getEc2RegionNames();
        EC2Region ec2RegionInfo = null;

        for (String ec2Region : ec2Regions) {

            ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2Region);

            try {
                ec2Instances = ec2RegionInfo.getRegionConnection().describeInstances(params);
            } catch (EC2Exception ex) {
                Logger.getLogger(EC2InstanceDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }

            for (ReservationDescription res : ec2Instances) {
                if (res.getInstances() != null) {
                    for (Instance inst : res.getInstances()) {
                        EC2Instance ec2Instance = new EC2Instance();
                        ec2Instance.setInstanceRegion(ec2Region);
                        ec2Instance.setinstanceId(inst.getInstanceId());
                        ec2Instance.setimageId(inst.getImageId());
                        ec2Instance.setprivateDnsName(inst.getPrivateDnsName());
                        ec2Instance.setdnsName(inst.getDnsName());
                        ec2Instance.setstateName(inst.getState());
                        ec2Instance.setavailabilityZone(inst.getAvailabilityZone());
                        ec2Instance.setlaunchTime(inst.getLaunchTime());
                        ec2Instance.setinstanceType(inst.getInstanceType());

                        if (sdbdomain != null) {
                            sdbattributes = (List<ItemAttribute>) sdbInstanceItems.get(inst.getInstanceId());
                            if (sdbattributes != null) {
                                if (sdbattributes.size() > 0) {
                                    for (ItemAttribute attribute : sdbattributes) {
                                        String attributename = attribute.getName();
                                        if (attributename.equals("name")) {
                                            ec2Instance.setinstname(attribute.getValue());
                                        } else if (attributename.equals("description")) {
                                            ec2Instance.setinstdesc(attribute.getValue());
                                        } else if (attributename.equals("ownernamelast")) {
                                            ec2Instance.setinstownernamelast(attribute.getValue());
                                        } else if (attributename.equals("ownernamefirst")) {
                                            ec2Instance.setinstownernamefirst(attribute.getValue());
                                        } else if (attributename.equals("ownerdept")) {
                                            ec2Instance.setinstownerdept(attribute.getValue());
                                        }
                                    }
                                }
                            }
                        }
                        getList().add(ec2Instance);
                    }
                }
            }
        }
    }

    public EC2Instance getInstance(RowKey rowKey) {
        EC2Instance ec2Instance = (EC2Instance) getObject(rowKey);
        return ec2Instance;
    }

    public EC2Instance getInstance(String id) {
        for (int i = 0; i < ec2InstanceList.size(); i++) {
            EC2Instance ec2Instance = (EC2Instance) ec2InstanceList.get(i);
            if (ec2Instance.getinstanceId().equals(id)) {
                return ec2Instance;
            }
        }
        return null;
    }

    public ArrayList getEC2InstanceIDsList() {
        ArrayList instancelist = new ArrayList();
        for (int i = 0; i < ec2InstanceList.size(); i++) {
            EC2Instance ec2Instance = (EC2Instance) ec2InstanceList.get(i);
            instancelist.add(ec2Instance.getinstanceId());
        }
        Collections.sort(instancelist);
        return instancelist;
    }

    public ArrayList getEC2InstanceIDsList(String state) {
        ArrayList instancelist = new ArrayList();
        for (int i = 0; i < ec2InstanceList.size(); i++) {
            EC2Instance ec2Instance = (EC2Instance) ec2InstanceList.get(i);
            if (ec2Instance.getstateName().equals(state)) {
                instancelist.add(ec2Instance.getinstanceId());
            }
        }
        Collections.sort(instancelist);
        return instancelist;
    }

    private int getInstanceIndex(String id) {
        for (int i = 0; i < ec2InstanceList.size(); i++) {
            EC2Instance ec2Instance = (EC2Instance) ec2InstanceList.get(i);
            if (ec2Instance.getinstanceId().equals(id)) {
                return i;
            }
        }
        return -1;
    }

    public Option[] getInstanceIDsOptions() {
        int i = 0;
        ArrayList runningInstances = new ArrayList();

        for (i = 0; i < ec2InstanceList.size(); i++) {
            EC2Instance ec2Instance = (EC2Instance) ec2InstanceList.get(i);
            if (ec2Instance.getstateName().equals("running")) {
                runningInstances.add(ec2Instance.getinstanceId());
            }
        }

        Option[] instanceIDsOptions = new Option[runningInstances.size() + 1];
        instanceIDsOptions[0] = new Option(null, "Select Instance ID");

        for (i = 0; i < runningInstances.size(); i++) {
            instanceIDsOptions[i + 1] = new Option(runningInstances.get(i));
        }
        return instanceIDsOptions;
    }

    public Option[] getImageIDsOptions() {
        int i = 0;
        ArrayList runningImages = new ArrayList();
        Map runningImagesMap = new HashMap();

        for (i = 0; i < ec2InstanceList.size(); i++) {
            EC2Instance ec2Instance = (EC2Instance) ec2InstanceList.get(i);
            if (runningImagesMap.get(ec2Instance.getimageId()) == null) {
                runningImages.add(ec2Instance.getimageId());
                runningImagesMap.put(ec2Instance.getimageId(), ec2Instance.getimageId());
            }
        }
        Option[] instanceImageIDsOptions = new Option[runningImages.size() + 1];
        instanceImageIDsOptions[0] = new Option(null, "Select Image ID");

        for (i = 0; i < runningImages.size(); i++) {
            instanceImageIDsOptions[i + 1] = new Option(runningImages.get(i));
        }

        return instanceImageIDsOptions;
    }

    public String deleteInstance(Map deleteInstanceInfo) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        String statusMsg = new String();
        ArrayList<RowKey> deleteInstsList = (ArrayList) deleteInstanceInfo.get("instRowKeys");
        ArrayList<String> ec2Regions = ec2connection.getEc2RegionNames();

        for (String ec2Region : ec2Regions) {

            List<String> ids = new ArrayList();
            EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2Region);

            for (int i = 0; i < deleteInstsList.size(); i++) {
                EC2Instance ec2Instance = this.getInstance(deleteInstsList.get(i));
                if (ec2Instance.getInstanceRegion().equals(ec2Region)) {
                    ids.add(ec2Instance.getinstanceId());
                }
            }

            if (ids.size() > 0) {
                List<InstanceStateChangeDescription> ec2TerminatingInstances = null;
                try {
                    ec2TerminatingInstances = ec2RegionInfo.getRegionConnection().terminateInstances(ids);
                    if (ec2TerminatingInstances != null) {
                        for (int j = 0; j < ec2TerminatingInstances.size(); j++) {
                            statusMsg = statusMsg + "\n";
                            statusMsg = statusMsg + "Instance ID: " + ec2TerminatingInstances.get(j).getInstanceId() + "\n";
                            statusMsg = statusMsg + "  Previous state: " + ec2TerminatingInstances.get(j).getPreviousState() + "\n";
                            statusMsg = statusMsg + "  Shutdown state: " + ec2TerminatingInstances.get(j).getCurrentState() + "\n";
                        }
                    } else {
                        statusMsg = "Shuuting down instances:\n\n";
                        for (int j = 0; j < ids.size(); j++) {
                            statusMsg = statusMsg + "  Instance ID: " + ids.get(j) + "\n";
                        }
                    }
                } catch (NullPointerException e) {
                    statusMsg = "Shuuting down instances:\n\n";
                    for (int j = 0; j < ids.size(); j++) {
                        statusMsg = statusMsg + "  Instance ID: " + ids.get(j) + "\n";
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    statusMsg = statusMsg + "  Error: " + e.getMessage() + "\n";
                }
            }
        }

        return statusMsg;
    }

    public String rebootInstance(Map rebootInstanceInfo) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        String statusMsg = new String();
        ArrayList<RowKey> rebootInstsList = (ArrayList) rebootInstanceInfo.get("instRowKeys");
        ArrayList<String> ec2Regions = ec2connection.getEc2RegionNames();

        for (String ec2Region : ec2Regions) {

            List<String> ids = new ArrayList();
            EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2Region);

            for (int i = 0; i < rebootInstsList.size(); i++) {
                EC2Instance ec2Instance = this.getInstance(rebootInstsList.get(i));
                if (ec2Instance.getInstanceRegion().equals(ec2Region)) {
                    ids.add(ec2Instance.getinstanceId());
                }
            }

            if (ids.size() > 0) {
                try {
                    ec2RegionInfo.getRegionConnection().rebootInstances(ids);
                    for (int i = 0; i < ids.size(); i++) {
                        statusMsg = statusMsg + "Rebooting instance: " + ids.get(i) + "\n";
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    statusMsg = statusMsg + "Error: " + e.getMessage() + "\n";
                }
            }
        }

        return statusMsg;
    }

    public String getConsoleOutput(Map getConsoleInstanceInfo) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        ArrayList<RowKey> getConsoleInstsList = (ArrayList) getConsoleInstanceInfo.get("instRowKeys");
        String consoleOutputStr = new String();

        for (int i = 0; i < getConsoleInstsList.size(); i++) {
            EC2Instance ec2Instance = this.getInstance(getConsoleInstsList.get(i));
            EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2Instance.getInstanceRegion());

            ConsoleOutput consoleOutput = null;
            try {
                consoleOutput = ec2RegionInfo.getRegionConnection().getConsoleOutput(ec2Instance.getinstanceId());
            } catch (EC2Exception ex) {
                Logger.getLogger(EC2InstanceDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }

            if (consoleOutput != null) {
                String instname = new String();
                if (ec2Instance.getinstname() != null) {
                    if (!ec2Instance.getinstname().equals("")) {
                        instname = " (" + ec2Instance.getinstname() + ") ";
                    }
                }
                consoleOutputStr = consoleOutputStr + "======== Instance Id: " + ec2Instance.getinstanceId() + instname + " Start ========\n";
                consoleOutputStr = consoleOutputStr + consoleOutput.getOutput() + "\n";
                consoleOutputStr = consoleOutputStr + "======== Instance Id: " + ec2Instance.getinstanceId() + instname + " End   ========\n\n";
            }
        }

        return consoleOutputStr;
    }

    public String updateInstance(Map instinfo) {

        int instIndex = -1;
        String statusMsg = new String();
        Item sdbitem = null;
        List<ItemAttribute> sdbattributes = new ArrayList<ItemAttribute>();

        String instid = (String) instinfo.get("instid");

        if (sdbdomain != null) {
            try {
                sdbitem = sdbdomain.getItem(instid);

                sdbattributes.add(new ItemAttribute("type", (String) instinfo.get("type"), true));
                sdbattributes.add(new ItemAttribute("createtime", (String) instinfo.get("instcreatetime"), true));
                sdbattributes.add(new ItemAttribute("name", (String) instinfo.get("instname"), true));
                sdbattributes.add(new ItemAttribute("description", (String) instinfo.get("instdesc"), true));
                sdbattributes.add(new ItemAttribute("ownernamelast", (String) instinfo.get("instownernamelast"), true));
                sdbattributes.add(new ItemAttribute("ownernamefirst", (String) instinfo.get("instownernamefirst"), true));
                sdbattributes.add(new ItemAttribute("ownerdept", (String) instinfo.get("instownerdept"), true));

                sdbitem.putAttributes(sdbattributes);

                EC2Instance ec2Instance = getInstance(instid);
                instIndex = getInstanceIndex(instid);

                ec2Instance.setinstname((String) instinfo.get("instname"));
                ec2Instance.setinstdesc((String) instinfo.get("instdesc"));
                ec2Instance.setinstownernamelast((String) instinfo.get("instownernamelast"));
                ec2Instance.setinstownernamefirst((String) instinfo.get("instownernamefirst"));
                ec2Instance.setinstownerdept((String) instinfo.get("instownerdept"));

                ec2InstanceList.set(instIndex, ec2Instance);

            } catch (SDBException ex) {
                Logger.getLogger(EC2InstanceDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return statusMsg;
    }
}
